home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 1 Issue 2 / PDCD-1 - Issue 02.iso / _utilities / utilities / 003 / _gs / !GS / c / GXCLIST < prev    next >
Text File  |  1991-10-26  |  25KB  |  842 lines

  1. /* Copyright (C) 1991 Aladdin Enterprises.  All rights reserved.
  2.    Distributed by Free Software Foundation, Inc.
  3.  
  4. This file is part of Ghostscript.
  5.  
  6. Ghostscript is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  8. to anyone for the consequences of using it or for whether it serves any
  9. particular purpose or works at all, unless he says so in writing.  Refer
  10. to the Ghostscript General Public License for full details.
  11.  
  12. Everyone is granted permission to copy, modify and redistribute
  13. Ghostscript, but only under the conditions described in the Ghostscript
  14. General Public License.  A copy of this license is supposed to have been
  15. given to you along with Ghostscript so you can know your rights and
  16. responsibilities.  It should be in a file named COPYING.  Among other
  17. things, the copyright notice and this notice must be preserved on all
  18. copies.  */
  19.  
  20. /* gxclist.c */
  21. /* Command list 'device' for Ghostscript. */
  22. #include "memory_.h"
  23. #include "gx.h"
  24. #include "gserrors.h"
  25. #include "gxbitmap.h"
  26. #include "gsmatrix.h"            /* for gxdevice.h */
  27. #include "gxdevice.h"
  28. #include "gxdevmem.h"            /* must precede gxclist.h */
  29. #include "gxclist.h"
  30.  
  31. /* Patch a couple of things possibly missing from stdio.h. */
  32. #ifndef SEEK_SET
  33. #  define SEEK_SET 0
  34. #endif
  35. #ifndef SEEK_CUR
  36. #  define SEEK_CUR 1
  37. #endif
  38.  
  39. /*
  40.  * The implementation here is somewhat lazy in that it requires the entire
  41.  * bitmap argument to copy_mono/color (in fact, all the scan lines involved)
  42.  * to fit into the tile_data buffer at once.
  43.  */
  44.  
  45. #define cdev ((gx_device_clist *)dev)
  46.  
  47. /* Forward declarations of procedures */
  48. private dev_proc_open_device(clist_open);
  49. private dev_proc_get_initial_matrix(clist_get_initial_matrix);
  50. private dev_proc_map_rgb_color(clist_map_rgb_color);
  51. private dev_proc_map_color_rgb(clist_map_color_rgb);
  52. private dev_proc_fill_rectangle(clist_fill_rectangle);
  53. private dev_proc_tile_rectangle(clist_tile_rectangle);
  54. private dev_proc_copy_mono(clist_copy_mono);
  55. private dev_proc_copy_color(clist_copy_color);
  56.  
  57. /* The device descriptor */
  58. private gx_device_procs clist_procs =
  59. {    clist_open,
  60.     clist_get_initial_matrix,
  61.     gx_default_sync_output,
  62.     gx_default_output_page,
  63.     gx_default_close_device,
  64.     clist_map_rgb_color,
  65.     clist_map_color_rgb,
  66.     clist_fill_rectangle,
  67.     clist_tile_rectangle,
  68.     clist_copy_mono,
  69.     clist_copy_color,
  70.     gx_default_draw_line,
  71.     gx_default_fill_trapezoid,
  72.     gx_default_tile_trapezoid
  73. };
  74. gx_device_clist gs_clist_device =
  75. {    sizeof(gx_device_clist),
  76.     &clist_procs,
  77.     "command list",
  78.     0, 0, 1, 1, no_margins, 0, 0, 0, 0,    /* generic */
  79.     NULL, NULL, 0
  80. };
  81.  
  82. /* ------ Define the command set and syntax ------ */
  83.  
  84. /* A command always consists of an operation followed by operands. */
  85. /* The operands are implicit in the procedural code. */
  86. typedef enum {
  87.     cmd_op_set_color0 = 0,        /* color+2 in op byte, [color] */
  88.     cmd_op_set_color1 = 0x10,    /* color+2 in op byte, [color] */
  89.     cmd_op_set_tile = 0x20,        /* raster, width, height, <bits> */
  90.     cmd_op_set_phase = 0x30,    /* x, y */
  91.     cmd_op_fill_rect = 0x40,    /* rect */
  92.     cmd_op_fill_rect_short = 0x50,    /* dh|0 in op byte, rect_short,[dh] */
  93.     cmd_op_fill_rect_tiny = 0x60,    /* dw in op byte, rect_tiny */
  94.     cmd_op_tile_rect = 0x70,    /* rect */
  95.     cmd_op_tile_rect_short = 0x80,    /* dh|0 in op byte, rect_short,[dh] */
  96.     cmd_op_tile_rect_tiny = 0x90,    /* dw in op byte, rect_tiny */
  97.     cmd_op_copy_mono = 0xa0,    /* rect, data_x, raster */
  98.     cmd_op_copy_color = 0xb0,    /* rect, data_x, raster */
  99.     cmd_op_end_run = 0xc0,        /* (nothing) */
  100.     cmd_op_end
  101. } gx_cmd_op;
  102. #ifdef DEBUG
  103. private char *cmd_op_names[16] = {
  104.   "set_color_0", "set_color_1", "set_tile", "set_phase",
  105.   "fill_rect", "fill_rect_short", "fill_rect_tiny", "tile_rect",
  106.   "tile_rect_short", "tile_rect_tiny", "copy_mono", "copy_color",
  107.   "end_run", "?d0?", "?e0?", "?f0?"
  108. };
  109. private ulong cmd_op_counts[256];
  110. private ulong cmd_tile_count, cmd_copy_count;
  111. private int
  112. count_op(int op)
  113. {    ++cmd_op_counts[op];
  114. #ifdef DEBUG
  115. if ( gs_debug['L'] )
  116.     dprintf2(", %s %d\n", cmd_op_names[op >> 4], op & 0xf);
  117. #endif
  118.     return op;
  119. }
  120. #else
  121. #  define count_op(store_op) store_op
  122. #endif
  123.  
  124. typedef struct {
  125.     short x, y, width, height;
  126. } gx_cmd_rect;
  127. typedef struct {
  128.     byte dx, dy, dwidth, dheight;    /* dheight is optional */
  129. } gx_cmd_rect_short;
  130. #define cmd_min_short (-128)
  131. #define cmd_max_short 127
  132. typedef struct {
  133.     unsigned dx : 4;
  134.     unsigned dy : 4;
  135. } gx_cmd_rect_tiny;
  136. #define cmd_min_tiny (-8)
  137. #define cmd_max_tiny 7
  138. /* Define the size of the largest command, */
  139. /* not counting any bitmap. */
  140. #define cmd_largest_size (1 + sizeof(gx_cmd_rect) + 4)
  141.  
  142. /* Define the prefix on each command in the buffer for writing. */
  143. typedef struct cmd_prefix_s cmd_prefix;
  144. struct cmd_prefix_s {
  145.     cmd_prefix *next;
  146.     uint size;
  147. };
  148.  
  149. /* Remember the current state of one band when writing or reading. */
  150. struct gx_clist_state_s {
  151.     gx_color_index color0, color1;    /* most recent colors */
  152.     gx_bitmap tile;            /* most recent tile */
  153.     gs_int_point phase;        /* most recent tile phase */
  154.     gx_cmd_rect rect;        /* most recent rectangle */
  155.     /* Following are only used when writing */
  156.     uint size;            /* total size of buffered commands */
  157.                     /* for this band */
  158.     uint band;            /* band number */
  159.     cmd_prefix *head, *tail;    /* list of commands for band */
  160. };
  161.  
  162. /* The initial values for a band state */
  163. private gx_clist_state cls_initial =
  164.    {    gx_no_color_index, gx_no_color_index,
  165.      { 0, 0, 0, 0 }, { 0, 0 }, { 0, 0, 0, 0 },
  166.     1, 0, 0, 0
  167.    };
  168.  
  169. /* Initialize the device state */
  170. private int
  171. clist_open(gx_device *dev)
  172. {    /*
  173.      * The buffer area (data, data_size) holds a tile cache when
  174.      * both writing and reading.  The rest of the space is used for
  175.      * the command buffer and band state bookkeeping when writing,
  176.      * and for the rendering buffer (image device) when reading.
  177.      * For the moment, we divide the space up arbitrarily.
  178.      */
  179.     byte *data = cdev->data;
  180.     uint size = cdev->data_size;
  181. #define alloc_data(n) data += (n), size -= (n)
  182.     gx_device *target = cdev->target;
  183.     int raster, nbands, band;
  184.     gx_clist_state *states;
  185.     uint state_size;
  186.     cdev->ymin = cdev->ymax = -1;    /* render_init not done yet */
  187.     cdev->tile_data = data;
  188.     cdev->tile_size = (size / 5) & -4;    /* arbitrary! */
  189.     alloc_data(cdev->tile_size);
  190.     raster = (((target->width * target->bits_per_color_pixel + 31) >> 5) << 2) + sizeof(byte *);
  191.     cdev->band_height = size / (uint)raster;
  192.     cdev->nbands = nbands = target->height / cdev->band_height + 1;
  193. #ifdef DEBUG
  194. if ( gs_debug['l'] | gs_debug['L'] )
  195.     dprintf4("[l]width=%d, raster=%d, band_height=%d, nbands=%d\n",
  196.              target->width, raster, cdev->band_height, cdev->nbands);
  197. #endif
  198.     state_size = nbands * sizeof(gx_clist_state);
  199.     if ( state_size > size / 2 )
  200.       return -1;        /* not enough room */
  201.     cdev->mdev.base = data;
  202.     cdev->states = states = (gx_clist_state *)data;
  203.     alloc_data(state_size);
  204.     cdev->cbuf = data;
  205.     cdev->cnext = data;
  206.     cdev->cend = data + size;
  207.     cdev->ccls = 0;
  208.     for ( band = 0; band < nbands; band++, states++ )
  209.       *states = cls_initial, states->band = band;
  210. #undef alloc_data
  211.     return 0;
  212. }
  213.  
  214. /* Forward the non-displaying operations to the target device. */
  215. private void
  216. clist_get_initial_matrix(gx_device *dev, gs_matrix *pmat)
  217. {    (*cdev->target->procs->get_initial_matrix)(dev, pmat);
  218. }
  219. private gx_color_index
  220. clist_map_rgb_color(gx_device *dev, ushort red, ushort green, ushort blue)
  221. {    return (*cdev->target->procs->map_rgb_color)(dev, red, green, blue);
  222. }
  223. private int
  224. clist_map_color_rgb(gx_device *dev, gx_color_index color, ushort rgb[3])
  225. {    return (*cdev->target->procs->map_color_rgb)(dev, color, rgb);
  226. }
  227.  
  228. /* Print a bitmap for tracing */
  229. #ifdef DEBUG
  230. private void
  231. cmd_print_bits(byte *data, int height, int raster)
  232. {    int i, j;
  233.     for ( i = 0; i < height; i++ )
  234.        {    byte *row = data + i * raster;
  235.         dprintf("[L]");
  236.         for ( j = 0; j < raster; j++ )
  237.           dprintf1(" %02x", row[j]);
  238.         dputc('\n');
  239.        }
  240. }
  241. #else
  242. #  define cmd_print_bits(data, height, raster)
  243. #endif
  244.  
  245. /* ------ Writing ------ */
  246.  
  247. /* Utilities */
  248.  
  249. #define cmd_set_rect(rect)\
  250.   ((rect).x = x, (rect).y = y,\
  251.    (rect).width = width, (rect).height = height)
  252.  
  253. private void
  254. clist_write(FILE *f, byte *str, uint len)
  255. {    fwrite(str, 1, len, f);
  256. }
  257.  
  258. /* Write out the buffered commands, and reset the buffer. */
  259. private void
  260. cmd_write_buffer(gx_device *dev)
  261. {    FILE *file = cdev->file;
  262.     int nbands = cdev->nbands;
  263.     gx_clist_state *pcls;
  264.     uint size = 0;
  265.     int band;
  266.     for ( band = 0, pcls = cdev->states; band < nbands; band++, pcls++ )
  267.       size += pcls->size;
  268. #ifdef DEBUG
  269. if ( gs_debug['l'] | gs_debug['L'] )
  270.     dprintf1("[l]write_buffer %d\n", size);
  271. #endif
  272.     if ( size == 0 ) return;        /* nothing to write */
  273.     clist_write(file, (byte *)&size, sizeof(size));
  274.     size = 0;
  275.     for ( band = 0, pcls = cdev->states; band < nbands; band++, pcls++ )
  276.        {    clist_write(file, (byte *)&size, sizeof(size));
  277.         size += pcls->size;
  278.        }
  279.     clist_write(file, (byte *)&size, sizeof(size));
  280.     for ( band = 0, pcls = cdev->states; band < nbands; band++, pcls++ )
  281.        {    cmd_prefix *cp = pcls->head;
  282.         for ( ; cp != 0; cp = cp->next )
  283.             clist_write(file, (byte *)(cp + 1), cp->size);
  284.         pcls->size = 1;
  285.         pcls->head = pcls->tail = 0;
  286.         fputc(cmd_op_end_run, file);
  287.        }
  288.     cdev->cnext = cdev->cbuf;
  289.     cdev->ccls = 0;
  290. }
  291.  
  292. /* Add a command to the appropriate band list, */
  293. /* and allocate space for its data. */
  294. /* Return the pointer to the data area. */
  295. private byte *
  296. cmd_put_op(gx_device *dev, gx_clist_state *pcls, uint size)
  297. {    byte *dp = cdev->cnext;
  298. #ifdef DEBUG
  299. if ( gs_debug['L'] )
  300.     dprintf3("[L]band %d: size=%d, left=%d",
  301.              pcls->band, size, (int)(cdev->cend - dp));
  302. #endif
  303.     if ( size + (sizeof(cmd_prefix) + 4) > cdev->cend - dp )
  304.       { cmd_write_buffer(dev);
  305.         return cmd_put_op(dev, pcls, size);
  306.       }
  307.     if ( cdev->ccls == pcls )
  308.       { /* We're adding another command for the same band. */
  309.         /* Tack it onto the end of the previous one. */
  310.         pcls->tail->size += size;
  311.       }
  312.     else
  313.       { cmd_prefix *cp = (cmd_prefix *)(dp + (((byte *)0 - dp) & 3));
  314.         dp = (byte *)(cp + 1);
  315.         if ( pcls->tail != 0 ) pcls->tail->next = cp;
  316.         else pcls->head = cp;
  317.         pcls->tail = cp;
  318.         cdev->ccls = pcls;
  319.         cp->next = 0;
  320.         cp->size = size;
  321.       }
  322.     cdev->cnext = dp + size;
  323.     pcls->size += size;
  324.     return dp;
  325. }
  326.  
  327. /* We store all short quantities little-endian. */
  328. /* This is OK, because we read them back little-endian explicitly. */
  329. #define cmd_putw(w, dp) (*dp = (w) & 0xff, dp[1] = (w) >> 8, dp += 2)
  330.  
  331. private int
  332. cmd_write_rect_cmd(gx_device *dev, gx_clist_state *pcls,
  333.   int op, int x, int y, int width, int height)
  334. {    int dx = x - pcls->rect.x;
  335.     int dy = y - pcls->rect.y;
  336.     int dwidth = width - pcls->rect.width;
  337.     int dheight = height - pcls->rect.height;
  338. #define check_ranges_1()\
  339.   ((unsigned)(dx - rmin) <= (rmax - rmin) &&\
  340.    (unsigned)(dy - rmin) <= (rmax - rmin) &&\
  341.    (unsigned)(dwidth - rmin) <= (rmax - rmin))
  342. #define check_ranges()\
  343.   (check_ranges_1() &&\
  344.    (unsigned)(dheight - rmin) <= (rmax - rmin))
  345. #define rmin cmd_min_tiny
  346. #define rmax cmd_max_tiny
  347.     cmd_set_rect(pcls->rect);
  348.     if ( dheight == 0 && check_ranges_1() )
  349.        {    byte *dp = cmd_put_op(dev, pcls, 2);
  350.         count_op(*dp = op + 0x20 + dwidth - rmin);
  351.         dp[1] = (dx << 4) + dy - (rmin * 0x11);
  352.        }
  353. #undef rmin
  354. #undef rmax
  355. #define rmin cmd_min_short
  356. #define rmax cmd_max_short
  357.     else if ( check_ranges() )
  358.        {    int dh = dheight - cmd_min_tiny;
  359.         byte *dp;
  360.         if ( (unsigned)dh <= cmd_max_tiny - cmd_min_tiny && dh != 0 )
  361.            {    op += dh;
  362.             dp = cmd_put_op(dev, pcls, 4);
  363.            }
  364.         else
  365.            {    dp = cmd_put_op(dev, pcls, 5);
  366.             dp[4] = dheight - rmin;
  367.            }
  368.         count_op(*dp = op + 0x10);
  369.         dp[1] = dx - rmin;
  370.         dp[2] = dy - rmin;
  371.         dp[3] = dwidth - rmin;
  372.        }
  373.     else
  374.        {    byte *dp = cmd_put_op(dev, pcls, 1 + sizeof(pcls->rect));
  375.         count_op(*dp = op);
  376.         memcpy(dp + 1, &pcls->rect, sizeof(pcls->rect));
  377.        }
  378.     return 0;
  379. }
  380.  
  381. private void
  382. cmd_put_color(gx_device *dev, gx_clist_state *pcls,
  383.   int op, gx_color_index color)
  384. {    if ( (long)color >= -1 && (long)color <= 13 )
  385.         count_op(*cmd_put_op(dev, pcls, 1) = op + (int)color + 2);
  386.     else
  387.        {    byte *dp = cmd_put_op(dev, pcls, 1 + sizeof(color));
  388.         count_op(*dp = op);
  389.         memcpy(dp + 1, &color, sizeof(color));
  390.        }
  391. }
  392. private void
  393. cmd_set_colors(gx_device *dev, gx_clist_state *pcls,
  394.   gx_color_index color0, gx_color_index color1)
  395. {    if ( color0 != pcls->color0 )
  396.        {    cmd_put_color(dev, pcls, cmd_op_set_color0, color0);
  397.         pcls->color0 = color0;
  398.        }
  399.     if ( color1 != pcls->color1 )
  400.        {    cmd_put_color(dev, pcls, cmd_op_set_color1, color1);
  401.         pcls->color1 = color1;
  402.        }
  403. }
  404.  
  405. /* Driver interface */
  406.  
  407. /* Macros for dividing up a single call into bands */
  408. #define BEGIN_RECT\
  409.    {    int yend = y + height;\
  410.     int band_height = cdev->band_height;\
  411.     do\
  412.        {    int band = y / band_height;\
  413.         gx_clist_state *pcls = cdev->states + band;\
  414.         height = band_height - y % band_height;\
  415.         if ( yend - y < height ) height = yend - y;\
  416.            {
  417. #define END_RECT\
  418.            }\
  419.         y += height;\
  420.        }\
  421.     while ( y < yend );\
  422.    }
  423.  
  424. private int
  425. clist_fill_rectangle(gx_device *dev, int x, int y, int width, int height,
  426.   gx_color_index color)
  427. {    BEGIN_RECT
  428.     if ( color != pcls->color1 )
  429.         cmd_set_colors(dev, pcls, pcls->color0, color);
  430.     cmd_write_rect_cmd(dev, pcls, cmd_op_fill_rect, x, y, width, height);
  431.     END_RECT
  432.     return 0;
  433. }
  434.  
  435. private int
  436. tile_eq(gx_bitmap *tile, gx_clist_state *pcls)
  437. {    return
  438.       (tile->data == pcls->tile.data &&
  439.        tile->raster == pcls->tile.raster &&
  440.        tile->width == pcls->tile.width &&
  441.        tile->height == pcls->tile.height);
  442. }
  443. private int
  444. clist_tile_rectangle(gx_device *dev, gx_bitmap *tile, int x, int y,
  445.   int width, int height, gx_color_index color0, gx_color_index color1,
  446.   int px, int py)
  447. {    uint tile_size = tile->raster * tile->height;
  448.     BEGIN_RECT
  449.     if ( color0 != pcls->color0 || color1 != pcls->color1 )
  450.         cmd_set_colors(dev, pcls, color0, color1);
  451.     if ( px != pcls->phase.x || py != pcls->phase.y )
  452.        {    byte *dp = cmd_put_op(dev, pcls, 1 + sizeof(pcls->phase));
  453.         count_op(*dp = (byte)cmd_op_set_phase);
  454.         pcls->phase.x = px;
  455.         pcls->phase.y = py;
  456.         memcpy(dp + 1, &pcls->phase, sizeof(pcls->phase));
  457.        }
  458.     if ( !tile_eq(tile, pcls) ||
  459.          memcmp(tile->data, cdev->tile_data, tile_size)
  460.        )
  461.        {    byte *dp = cmd_put_op(dev, pcls, 1 + 6 + tile_size);
  462.         count_op(*dp++ = (byte)cmd_op_set_tile);
  463.         cmd_putw(tile->raster, dp);
  464.         cmd_putw(tile->width, dp);
  465.         cmd_putw(tile->height, dp);
  466.         if ( tile_size <= cdev->tile_size )
  467.            {    /* Clear the tile records of all the other bands. */
  468.                {    gx_clist_state *tcls = cdev->states;
  469.                 int i;
  470.                 for ( i = 0; i < cdev->nbands; i++, tcls++ )
  471.                   tcls->tile.data = 0;
  472.                }
  473.             pcls->tile = *tile;
  474.             memcpy(cdev->tile_data, tile->data, tile_size);
  475.            }
  476.         memcpy(dp, tile->data, tile_size);
  477. #ifdef DEBUG
  478.         cmd_tile_count += tile_size;
  479. #endif
  480.        }
  481.     cmd_write_rect_cmd(dev, pcls, cmd_op_tile_rect, x, y, width, height);
  482.     END_RECT
  483.     return 0;
  484. }
  485.  
  486. private int
  487. clist_copy_mono(gx_device *dev, byte *data, int data_x, int raster,
  488.     int x, int y, int width, int height,
  489.     gx_color_index color0, gx_color_index color1)
  490. {    int y0 = y;
  491.     BEGIN_RECT
  492.     gx_cmd_rect rect;
  493.     uint dsize = height * raster;
  494.     byte *dp;
  495.     if ( color0 != pcls->color0 || color1 != pcls->color1 )
  496.         cmd_set_colors(dev, pcls, color0, color1);
  497.     cmd_set_rect(rect);
  498.     dp = cmd_put_op(dev, pcls, 1 + sizeof(rect) + 4 + dsize);
  499.     count_op(*dp++ = (byte)cmd_op_copy_mono);
  500.     memcpy(dp, (byte *)&rect, sizeof(rect));
  501.     pcls->rect = rect;
  502.     dp += sizeof(rect);
  503.     cmd_putw(data_x, dp);
  504.     cmd_putw(raster, dp);
  505.     memcpy(dp, data + (y - y0) * raster, dsize);
  506. #ifdef DEBUG
  507.     cmd_copy_count += dsize;
  508. #endif
  509.     END_RECT
  510.     return 0;
  511. }
  512.  
  513. private int
  514. clist_copy_color(gx_device *dev, byte *data, int data_x, int raster,
  515.     int x, int y, int width, int height)
  516. {    int y0 = y;
  517.     BEGIN_RECT
  518.     gx_cmd_rect rect;
  519.     uint dsize = height * raster;
  520.     byte *dp;
  521.     cmd_set_rect(rect);
  522.     dp = cmd_put_op(dev, pcls, 1 + sizeof(rect) + 4 + dsize);
  523.     count_op(*dp++ = (byte)cmd_op_copy_color);
  524.     memcpy(dp, (byte *)&rect, sizeof(rect));
  525.     pcls->rect = rect;
  526.     dp += sizeof(rect);
  527.     cmd_putw(data_x, dp);
  528.     cmd_putw(raster, dp);
  529.     memcpy(dp, data + (y - y0) * raster, dsize);
  530.     END_RECT
  531.     return 0;
  532. }
  533.  
  534. /* ------ Reading/rendering ------ */
  535.  
  536. #undef cdev
  537.  
  538. private int clist_render(P3(gx_device_clist *, gx_device *, int));
  539.  
  540. /* Initialize for reading. */
  541. int
  542. clist_render_init(gx_device_clist *cdev)
  543. {    gx_device *target = cdev->target;
  544.     byte *base = cdev->mdev.base;    /* save */
  545.     int bpp = target->bits_per_color_pixel;
  546.     uint raster = ((target->width * bpp + 31) >> 5) << 2;
  547.     gx_device_memory *mdev;
  548.     cmd_write_buffer((gx_device *)cdev);    /* flush buffer */
  549.     switch ( bpp )
  550.        {
  551.     case 1: mdev = &mem_mono_device; break;
  552.     case 8: mdev = &mem_mapped8_color_device; break;
  553.     case 24: mdev = &mem_true24_color_device; break;
  554.     case 32: mdev = &mem_true32_color_device; break;
  555.     default: return_error(gs_error_rangecheck);
  556.        }
  557.     cdev->mdev = *mdev;
  558.     cdev->mdev.base = base;        /* restore */
  559.     (*target->procs->get_initial_matrix)(target, &cdev->mdev.initial_matrix);
  560.     cdev->mdev.width = target->width;
  561.     cdev->mdev.height = cdev->band_height;
  562.     cdev->mdev.raster = raster;
  563.     cdev->ymin = cdev->ymax = 0;
  564. #ifdef DEBUG
  565. if ( gs_debug['l'] | gs_debug['L'] )
  566.    {    int ci, cj;
  567.     dprintf2("[l]counts: tile = %ld, copy = %ld\n",
  568.              cmd_tile_count, cmd_copy_count);
  569.     for ( ci = 0; ci < 0x100; ci += 0x10 )
  570.        {    dprintf1("[l]  %s =", cmd_op_names[ci >> 4]);
  571.         for ( cj = ci; cj < ci + 0x10; cj++ )
  572.             dprintf1(" %ld", cmd_op_counts[cj]);
  573.         dputs("\n");
  574.        }
  575.    }
  576. #endif
  577.     return 0;
  578. }
  579.  
  580. /* Copy scan lines to the client.  This is where rendering gets done. */
  581. int
  582. clist_copy_scan_lines(gx_device_clist *cdev, int start_y,
  583.   byte *str, uint size)
  584. {    gx_device_memory *mdev = &cdev->mdev;
  585.     uint bytes_per_line = gdev_mem_bytes_per_scan_line((gx_device *)mdev);
  586.     uint count = min(size / bytes_per_line,
  587.              cdev->target->height - start_y);
  588.     int y = start_y;
  589.     uint left = count;
  590.     byte *dest = str;
  591.     /* Render bands and copy them incrementally. */
  592.     while ( left )
  593.        {    int n;
  594.         if ( !(y >= cdev->ymin && y < cdev->ymax) )
  595.            {    int band = y / mdev->height;
  596.             rewind(cdev->file);
  597.             (*mdev->procs->open_device)((gx_device *)mdev);    /* reinitialize */
  598.             clist_render(cdev, (gx_device *)mdev, band);
  599.             gdev_mem_ensure_byte_order(mdev);
  600.             cdev->ymin = band * mdev->height;
  601.             cdev->ymax = cdev->ymin + mdev->height;
  602.            }
  603.         n = min(cdev->ymax - y, left);
  604.         gdev_mem_copy_scan_lines(mdev, y - cdev->ymin, dest,
  605.                      bytes_per_line * n);
  606.         y += n, dest += bytes_per_line * n, left -= n;
  607.        }
  608.     return count;
  609. }
  610.  
  611. /* Render one band to a specified target device. */
  612. #define assign_getw(var, p)\
  613.   (var = *p + ((uint)p[1] << 8), p += 2)
  614. #define cbuf_size 500
  615. private void clist_read(P3(FILE *, byte *, uint));
  616. private void clist_skip(P2(FILE *, uint));
  617. private int
  618. clist_render(gx_device_clist *cdev, gx_device *tdev, int band)
  619. {    byte cbuf[cbuf_size];
  620.     register byte _ss *cbp;
  621.     byte _ss *cb_limit;
  622.     byte _ss *cb_end;
  623.     FILE *file = cdev->file;
  624.     int y0 = band * cdev->band_height;
  625.     gx_clist_state state;
  626.     gs_int_point tile_phase;
  627.     long end_run;
  628.     uint left;
  629. #define cmd_read_var(ptr, cbp)\
  630.   memcpy(ptr, cbp, sizeof(*ptr)),\
  631.   cbp += sizeof(*ptr)
  632. #define cmd_read(ptr, vsize, cbp)\
  633.   if ( cb_end - cbp >= vsize )\
  634.     memcpy(ptr, cbp, vsize), cbp += vsize;\
  635.   else\
  636.    { uint cleft = cb_end - cbp;\
  637.      memcpy(ptr, cbp, cleft); vsize -= cleft;\
  638.      clist_read(file, ptr + cleft, vsize);\
  639.      cbp = cb_end;\
  640.    }
  641.     state = cls_initial;
  642.     tile_phase.x = tile_phase.y = 0;
  643.     state.tile.data = cdev->tile_data;
  644.     state.tile.width = state.tile.height = 1;    /* so set_phase works */
  645. #ifdef DEBUG
  646. if ( gs_debug['l'] | gs_debug['L'] )
  647.     dprintf1("[l]render band %d\n", band);
  648. #endif
  649.     /* Read the header of a block of buffered commands, */
  650.     /* and skip to the correct run for this band. */
  651. top:       {    uint block_size, start[2];
  652.         clist_read(file, (byte *)&block_size, sizeof(block_size));
  653. #ifdef DEBUG
  654. if ( gs_debug['l'] | gs_debug['L'] )
  655.         dprintf2("[l]block at %ld, size=%d\n",
  656.              ftell(file), block_size);
  657. #endif
  658.         if ( feof(file) ) return 0;    /* all done */
  659.         end_run = ftell(file) + (cdev->nbands + 1) * sizeof(uint) +
  660.             (ulong)block_size;
  661.         clist_skip(file, band * sizeof(uint));
  662.         clist_read(file, (byte *)start, sizeof(start));
  663.         left = start[1] - start[0];
  664.         clist_skip(file, (cdev->nbands - band - 1) * sizeof(uint) + start[0]);
  665. #ifdef DEBUG
  666. if ( gs_debug['l'] | gs_debug['L'] )
  667.         dprintf4("[l]start=%d,%d run=%ld, end_run=%ld\n",
  668.                  start[0], start[1], ftell(file), end_run);
  669. #endif
  670.        }
  671.     cb_limit = cbuf + (cbuf_size - cmd_largest_size);
  672.     cb_end = cbuf + cbuf_size;
  673.     cbp = cb_end;
  674.     for ( ; ; )
  675.        {    int op;
  676.         uint bytes;
  677.         int code;
  678.         gx_color_index _ss *pcolor;
  679.         /* Make sure the buffer contains a full command. */
  680.         if ( cbp > cb_limit )
  681.            {    uint nread;
  682.             memcpy(cbuf, cbp, cb_end - cbp);
  683.             cbp = cbuf + (cb_end - cbp);
  684.             nread = cb_end - cbp;
  685.             if ( nread > left ) nread = left;
  686.             clist_read(file, cbp, nread);
  687.             cb_end = cbp + nread;
  688.             cbp = cbuf;
  689.             left -= nread;
  690.             if ( cb_limit > cb_end ) cb_limit = cb_end;
  691.            }
  692.         op = *cbp++;
  693. #ifdef DEBUG
  694. if ( gs_debug['L'] )
  695.         dprintf2("[L]%s %d:\n", cmd_op_names[op >> 4], op & 0xf);
  696. #endif
  697.         switch ( op >> 4 )
  698.            {
  699.         case cmd_op_set_color0 >> 4:
  700.             pcolor = &state.color0;
  701.             goto set_color;
  702.         case cmd_op_set_color1 >> 4:
  703.             pcolor = &state.color1;
  704. set_color:        if ( op & 0xf )
  705.                 *pcolor = (gx_color_index)(long)((op & 0xf) - 2);
  706.             else
  707.                 cmd_read_var(pcolor, cbp);
  708.             continue;
  709.         case cmd_op_set_tile >> 4:
  710.             assign_getw(state.tile.raster, cbp);
  711.             assign_getw(state.tile.width, cbp);
  712.             assign_getw(state.tile.height, cbp);
  713.             bytes = state.tile.height * state.tile.raster;
  714.             cmd_read(state.tile.data, bytes, cbp);
  715. #ifdef DEBUG
  716. if ( gs_debug['L'] )
  717.             cmd_print_bits(state.tile.data, state.tile.height,
  718.                        state.tile.raster);
  719. #endif
  720.             goto set_phase;
  721.         case cmd_op_set_phase >> 4:
  722.             cmd_read_var(&state.phase, cbp);
  723. set_phase:        tile_phase.x = state.phase.x % state.tile.width;
  724.             tile_phase.y = (state.phase.y + y0) % state.tile.height;
  725.             continue;
  726.         case cmd_op_fill_rect >> 4:
  727.         case cmd_op_tile_rect >> 4:
  728.         case cmd_op_copy_mono >> 4:
  729.         case cmd_op_copy_color >> 4:
  730.             cmd_read_var(&state.rect, cbp);
  731.             break;
  732.         case cmd_op_fill_rect_short >> 4:
  733.         case cmd_op_tile_rect_short >> 4:
  734.             state.rect.x += *cbp + cmd_min_short;
  735.             state.rect.y += cbp[1] + cmd_min_short;
  736.             state.rect.width += cbp[2] + cmd_min_short;
  737.             state.rect.height +=
  738.               (op & 0xf ? (op & 0xf) + cmd_min_tiny :
  739.                (++cbp)[2] + cmd_min_short);
  740.             cbp += 3;
  741.             break;
  742.         case cmd_op_fill_rect_tiny >> 4:
  743.         case cmd_op_tile_rect_tiny >> 4:
  744.            {    int txy = *cbp++;
  745.             state.rect.x += (txy >> 4) + cmd_min_tiny;
  746.             state.rect.y += (txy & 0xf) + cmd_min_tiny;
  747.             state.rect.width += (op & 0xf) + cmd_min_tiny;
  748.            }    break;
  749.         case cmd_op_end_run >> 4:
  750.             fseek(file, end_run, SEEK_SET);    /* skip rest of block */
  751.             goto top;
  752.         default:
  753.             lprintf5("Bad op %02x band %d file pos %ld buf pos %d/%d\n",
  754.                  op, band, ftell(file), (int)(cbp - cbuf), (int)(cb_end - cbuf));
  755.             return -1;
  756.            }
  757. #ifdef DEBUG
  758. if ( gs_debug['L'] )
  759.         dprintf4("[L]  x=%d y=%d w=%d h=%d\n",
  760.              state.rect.x, state.rect.y, state.rect.width,
  761.              state.rect.height);
  762. #endif
  763.         switch ( op >> 4 )
  764.            {
  765.         case cmd_op_fill_rect >> 4:
  766.         case cmd_op_fill_rect_short >> 4:
  767.         case cmd_op_fill_rect_tiny >> 4:
  768.             code = (*tdev->procs->fill_rectangle)
  769.               (tdev, state.rect.x, state.rect.y - y0,
  770.                state.rect.width, state.rect.height, state.color1);
  771.             break;
  772.         case cmd_op_tile_rect >> 4:
  773.         case cmd_op_tile_rect_short >> 4:
  774.         case cmd_op_tile_rect_tiny >> 4:
  775.             code = (*tdev->procs->tile_rectangle)
  776.               (tdev, &state.tile,
  777.                state.rect.x, state.rect.y - y0,
  778.                state.rect.width, state.rect.height,
  779.                state.color0, state.color1,
  780.                tile_phase.x, tile_phase.y);
  781.             break;
  782.         case cmd_op_copy_mono >> 4:
  783.         case cmd_op_copy_color >> 4:
  784.            {    int data_x, raster;
  785.             assign_getw(data_x, cbp);
  786.             assign_getw(raster, cbp);
  787. #ifdef DEBUG
  788. if ( gs_debug['L'] )
  789.             dprintf2("[L]  data_x=%d raster=%d\n",
  790.                  data_x, raster);
  791. #endif
  792.             bytes = state.rect.height * raster;
  793.             /* The following doesn't work for very large */
  794.             /* bitmaps, but it's good enough for now. */
  795.             cmd_read(cbuf, bytes, cbp);
  796. #ifdef DEBUG
  797. if ( gs_debug['L'] )
  798.             cmd_print_bits(cbuf, state.rect.height, raster);
  799. #endif
  800.             code = (op >> 4 == (byte)cmd_op_copy_mono >> 4 ?
  801.               (*tdev->procs->copy_mono)
  802.                 (tdev, cbuf, data_x, raster,
  803.                  state.rect.x, state.rect.y - y0,
  804.                  state.rect.width, state.rect.height,
  805.                  state.color0, state.color1) :
  806.               (*tdev->procs->copy_color)
  807.                 (tdev, cbuf, data_x, raster,
  808.                  state.rect.x, state.rect.y - y0,
  809.                  state.rect.width, state.rect.height));
  810.            }    break;
  811.            }
  812.         if ( code < 0 ) return code;
  813.        }
  814. }
  815. /* The typical implementations of fread and fseek */
  816. /* are extremely inefficient for small counts, */
  817. /* so we use loops instead. */
  818. private void
  819. clist_read(FILE *f, byte *str, uint len)
  820. {    switch ( len )
  821.        {
  822.     default: fread(str, 1, len, f); break;
  823.     case 8: *str++ = (char)getc(f);
  824.     case 7: *str++ = (char)getc(f);
  825.     case 6: *str++ = (char)getc(f);
  826.     case 5: *str++ = (char)getc(f);
  827.     case 4: *str++ = (char)getc(f);
  828.     case 3: *str++ = (char)getc(f);
  829.     case 2: *str++ = (char)getc(f);
  830.     case 1: *str = (char)getc(f);
  831.        }
  832. }
  833. private void
  834. clist_skip(FILE *f, uint len)
  835. {    if ( len <= 10 )
  836.        {    register int i;
  837.         for ( i = 0; i < len; i++ ) getc(f);
  838.        }
  839.     else
  840.         fseek(f, (long)len, SEEK_CUR);
  841. }
  842.